//
// Copyright 2017 Google Inc.
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.
//

// stylelint-disable selector-class-pattern --
// Selector '.mdc-*' should only be used in this project.

@use 'sass:math';
@use 'sass:list';
@use 'sass:meta';
@use 'sass:map';
@use '@material/animation/animation';
@use '@material/theme/css';
@use '@material/density/functions' as density-functions;
@use '@material/dom/dom';
@use '@material/floating-label/mixins' as floating-label-mixins;
@use '@material/floating-label/variables' as floating-label-variables;
@use '@material/line-ripple/mixins' as line-ripple-mixins;
@use '@material/notched-outline/mixins' as notched-outline-mixins;
@use '@material/notched-outline/variables' as notched-outline-variables;
@use '@material/ripple/ripple';
@use '@material/ripple/ripple-theme';
@use '@material/theme/custom-properties';
@use '@material/theme/theme';
@use '@material/shape/mixins' as shape-mixins;
@use '@material/shape/functions' as shape-functions;
@use '@material/feature-targeting/feature-targeting';
@use '@material/typography/typography';
@use 'helper-text/mixins' as helper-text-mixins;
@use 'character-counter/mixins' as character-counter-mixins;
@use 'icon/mixins' as icon-mixins;
@use 'icon/variables' as icon-variables;
@use './variables';
@use '@material/rtl/rtl';

$_density-config: map.merge(
  variables.$density-config,
  (
    minimum: math.min(variables.$minimum-height, 36px),
  )
);

@mixin core-styles($query: feature-targeting.all()) {
  @include ripple($query);
  @include static-styles($query);
  @include helper-text-mixins.helper-text-core-styles($query);
  @include character-counter-mixins.character-counter-core-styles($query);
  @include icon-mixins.icon-core-styles($query);
}

/// @deprecated Use static-styles() instead.
@mixin without-ripple($query: feature-targeting.all()) {
  @include static-styles($query);
}

@mixin static-styles($query: feature-targeting.all()) {
  $feat-structure: feature-targeting.create-target($query, structure);

  // Baseline
  // postcss-bem-linter: define text-field
  .mdc-text-field {
    @include _base($query);
  }

  .mdc-text-field__input {
    @include _input($query);

    @include placeholder-selector_ {
      @include _input-placeholder($query);
    }

    // Always show placeholder for text fields that has no
    // label and show only on focused state when label is present.
    .mdc-text-field--no-label &,
    .mdc-text-field--focused & {
      @include placeholder-selector_ {
        @include _input-placeholder-visible($query);
      }
    }
  }

  .mdc-text-field__affix {
    @include _affix($query: $query);

    .mdc-text-field--label-floating &,
    .mdc-text-field--no-label & {
      @include _affix-visible($query: $query);
    }

    // Safari only
    @supports (-webkit-hyphens: none) {
      .mdc-text-field--outlined & {
        @include _centered-affix-safari-support($query: $query);
      }
    }
  }

  .mdc-text-field__affix--prefix {
    @include _prefix($query: $query);

    .mdc-text-field--end-aligned & {
      @include _prefix-end-aligned($query: $query);
    }
  }

  .mdc-text-field__affix--suffix {
    @include _suffix($query: $query);

    .mdc-text-field--end-aligned & {
      @include _suffix-end-aligned($query: $query);
    }
  }

  // Variants

  .mdc-text-field--filled {
    @include _filled($query);

    &.mdc-text-field--no-label {
      @include filled-no-label($query);
    }
  }

  .mdc-text-field--outlined {
    @include outlined_($query);

    .mdc-notched-outline {
      @include _outlined-notched-outline($query);
    }
  }

  // Other Variations

  .mdc-text-field--textarea {
    @include textarea_($query);

    .mdc-text-field__input {
      @include _textarea-input($query);
    }

    &.mdc-text-field--filled {
      @include _textarea-filled($query);

      .mdc-text-field__input {
        @include _textarea-filled-input($query);
      }

      &.mdc-text-field--no-label {
        .mdc-text-field__input {
          @include _textarea-filled-no-label-input($query);
        }
      }
    }

    &.mdc-text-field--outlined {
      @include _textarea-outlined($query);

      .mdc-text-field__input {
        @include _textarea-outlined-input($query);
      }

      .mdc-floating-label {
        @include _textarea-outlined-floating-label($query);
      }
    }

    &.mdc-text-field--with-internal-counter {
      .mdc-text-field__input {
        @include _textarea-input-with-internal-counter($query);
      }

      .mdc-text-field-character-counter {
        @include _textarea-internal-counter($query);
      }
    }
  }

  // Resizer element does not need to be under mdc-text-field--textarea, that
  // just adds specificity
  .mdc-text-field__resizer {
    @include _textarea-resizer($query);

    .mdc-text-field--filled & {
      @include _textarea-filled-resizer($query);

      .mdc-text-field__input,
      .mdc-text-field-character-counter {
        @include _textarea-filled-resizer-children($query);
      }
    }

    .mdc-text-field--outlined & {
      @include _textarea-outlined-resizer($query);

      .mdc-text-field__input,
      .mdc-text-field-character-counter {
        @include _textarea-outlined-resizer-children($query);
      }
    }
  }

  .mdc-text-field--with-leading-icon {
    @include _padding-horizontal-with-leading-icon($query);

    &.mdc-text-field--filled {
      @include with-leading-icon_($query);
    }

    &.mdc-text-field--outlined {
      @include outlined-with-leading-icon_($query);
    }
  }

  .mdc-text-field--with-trailing-icon {
    @include _padding-horizontal-with-trailing-icon($query);

    &.mdc-text-field--filled {
      @include _with-trailing-icon($query);
    }

    &.mdc-text-field--outlined {
      @include _outlined-with-trailing-icon($query);
    }
  }

  .mdc-text-field--with-leading-icon.mdc-text-field--with-trailing-icon {
    @include _padding-horizontal-with-both-icons($query);

    &.mdc-text-field--filled {
      @include _with-leading-and-trailing-icon($query);
    }
  }

  // postcss-bem-linter: define text-field-helper-text
  .mdc-text-field-helper-line {
    @include feature-targeting.targets($feat-structure) {
      display: flex;
      justify-content: space-between;
      box-sizing: border-box;
    }

    .mdc-text-field + & {
      @include feature-targeting.targets($feat-structure) {
        padding-right: variables.$helper-line-padding;
        padding-left: variables.$helper-line-padding;
      }
    }
  }
  // postcss-bem-linter: end

  // mdc-form-field tweaks to align text field label correctly
  // stylelint-disable selector-max-type --
  // TODO: document why this disable is neccessary
  .mdc-form-field > .mdc-text-field + label {
    @include feature-targeting.targets($feat-structure) {
      align-self: flex-start;
    }
  }
  // stylelint-enable selector-max-type

  // States
  .mdc-text-field--focused {
    @include focused_($query);

    &.mdc-text-field--outlined {
      @include _focused-outlined($query);

      &.mdc-text-field--textarea {
        @include _focused-outlined-textarea($query);
      }
    }
  }

  .mdc-text-field--invalid {
    @include invalid_($query);
  }

  .mdc-text-field--disabled {
    @include disabled_($query);

    &.mdc-text-field--filled {
      @include _disabled-filled($query);
    }

    .mdc-text-field__input {
      @include _disabled-input($query);
    }
  }

  .mdc-text-field--end-aligned {
    @include end-aligned_($query);
  }

  .mdc-text-field--ltr-text {
    @include _ltr-text($query);

    &.mdc-text-field--end-aligned {
      @include _ltr-text-end-aligned($query);
    }
  }
}

// This API is intended for use by frameworks that may want to separate the ripple-related styles
// from the other text field styles. It is recommended that most users use `mdc-text-field-core-styles` instead.
@mixin ripple($query: feature-targeting.all()) {
  @include ripple.common($query); // COPYBARA_COMMENT_THIS_LINE

  .mdc-text-field--filled {
    @include ripple.surface(
      $query: $query,
      $ripple-target: variables.$ripple-target
    );
    @include ripple.radius-bounded(
      $query: $query,
      $ripple-target: variables.$ripple-target
    );
  }

  #{variables.$ripple-target} {
    @include ripple.target-common($query: $query);
  }
}

///
/// Sets density scale for default text field variant.
///
/// @param {Number | String} $density-scale - Density scale value for component. Supported density scale values `-4`,
///     `-3`, `-2`, `-1`, `0`. Default is `0`.
/// @param {Number} $minimum-height-for-filled-label Sets the minimum height for
///     filled textfields at which to allow floating labels.
///
@mixin density(
  $density-scale,
  $minimum-height-for-filled-label: variables.$minimum-height-for-filled-label,
  $query: feature-targeting.all()
) {
  $height: density-functions.prop-value(
    $density-config: $_density-config,
    $density-scale: $density-scale,
    $property-name: height,
  );

  @include height(
    $height,
    $minimum-height-for-filled-label: $minimum-height-for-filled-label,
    $query: $query
  );
  // TODO(b/151839219): resize icons and adjust label position
  // @if $density-scale < 0 {
  //   @include icon-mixins.size(icon-variables.$dense-icon-size);
  // }
}

///
/// Sets density scale for outlined text field (Excluding outlined text field with leading icon).
///
/// @param {Number | String} $density-scale - Density scale value for component. Supported density scale values `-4`,
///     `-3`, `-2`, `-1`, `0`. Default is `0`.
/// @param {Number} $label-font-size - Font-size for the textfield's floating label. If the label size is being customized, it is necessary to specify this value to ensure that the notched outline does not cut-off the label when floated, see b/302340517 for more info. Defaults to 1rem.
///
@mixin outlined-density(
  $density-scale,
  $label-font-size: 1rem,
  $query: feature-targeting.all()
) {
  $height: density-functions.prop-value(
    $density-config: $_density-config,
    $density-scale: $density-scale,
    $property-name: height,
  );

  @include outlined-height(
    $height,
    $label-font-size: $label-font-size,
    $query: $query
  );
  // TODO(b/151839219): resize icons and adjust label position
  // @if $density-scale < 0 {
  //   @include icon-mixins.size(icon-variables.$dense-icon-size);
  // }
}

///
/// Sets density scale for outlined text field with leading icon.
///
/// @param {Number | String} $density-scale - Density scale value for component. Supported density scale values `-4`,
///     `-3`, `-2`, `-1`, `0`. Default is `0`.
/// @param {Number} $label-font-size - Font-size for the textfield's floating label. It is necessary tto specify this value to ensure that the notched outline does not cut-off the label when floated, see b/302340517 for more info.
///
@mixin outlined-with-leading-icon-density(
  $density-scale,
  $label-font-size: 1rem,
  $query: feature-targeting.all()
) {
  $height: density-functions.prop-value(
    $density-config: $_density-config,
    $density-scale: $density-scale,
    $property-name: height,
  );

  @include outlined-with-leading-icon-height(
    $height,
    $label-font-size: $label-font-size,
    $query: $query
  );
  // TODO(b/151839219): resize icons and adjust label position
  // @if $density-scale < 0 {
  //   @include icon-mixins.size(icon-variables.$dense-icon-size);
  // }
}

///
/// Sets density scale for filled textarea.
///
/// @param {Number | String} $density-scale - Density scale value for component. Supported density scale values `-4`,
///     `-3`, `-2`, `-1`, `0`. Default is `0`.
///
@mixin filled-textarea-density(
  $density-scale,
  $query: feature-targeting.all()
) {
  $feat-structure: feature-targeting.create-target($query, structure);
  $textfield-height: density-functions.prop-value(
    $density-config: $_density-config,
    $density-scale: $density-scale,
    $property-name: height,
  );
  $no-label-margin-top: density-functions.prop-value(
    $density-config: variables.$textarea-filled-no-label-density-config,
    $density-scale: math.div($density-scale, 2),
    $property-name: margin-top,
  );
  $no-label-margin-bottom: density-functions.prop-value(
    $density-config: variables.$textarea-filled-no-label-density-config,
    $density-scale: math.div($density-scale, 2),
    $property-name: margin-bottom,
  );

  // Textarea mixins require two modifier classes since two are used internally
  // for styles (textarea and filled). An extra class is added for the public
  // mixin so that only a single public class is needed for specificity.
  &.mdc-text-field--filled {
    .mdc-text-field__resizer {
      @include feature-targeting.targets($feat-structure) {
        min-height: $textfield-height;
      }
    }

    @if $density-scale >= -1 {
      $keyframe-suffix: text-field-filled-#{$density-scale};
      $label-top: density-functions.prop-value(
        $density-config: variables.$textarea-filled-label-density-config,
        $density-scale: math.div($density-scale, 2),
        $property-name: top,
      );

      // Adjust the floating position and animation/keyframes of the floating
      // label by the new position of the resting label
      $label-top-difference: variables.$textarea-outlined-label-top -
        $label-top;

      // Floating label position
      @include floating-label-mixins.float-position(
        variables.$textarea-filled-label-position-y - $label-top-difference,
        $query: $query
      );

      // Floating label animation
      @include floating-label-mixins.shake-animation(
        $keyframe-suffix,
        $query: $query
      );
      @at-root {
        @include floating-label-mixins.shake-keyframes(
          $keyframe-suffix,
          variables.$textarea-filled-label-position-y - $label-top-difference,
          0%,
          $query: $query
        );
      }

      // Resting label position
      .mdc-floating-label {
        @include feature-targeting.targets($feat-structure) {
          top: $label-top;
        }
      }

      $margin-bottom: density-functions.prop-value(
        $density-config: variables.$textarea-filled-density-config,
        $density-scale: $density-scale,
        $property-name: margin-bottom,
      );

      .mdc-text-field__input {
        @include feature-targeting.targets($feat-structure) {
          margin-bottom: $margin-bottom;
        }
      }
    } @else {
      // The textarea is too dense to show a floating label
      .mdc-floating-label {
        @include feature-targeting.targets($feat-structure) {
          display: none;
        }
      }

      .mdc-text-field__input {
        @include feature-targeting.targets($feat-structure) {
          margin-top: $no-label-margin-top;
          margin-bottom: $no-label-margin-bottom;
        }
      }
    }

    &.mdc-text-field--no-label {
      .mdc-text-field__input {
        @include feature-targeting.targets($feat-structure) {
          margin-top: $no-label-margin-top;
          margin-bottom: $no-label-margin-bottom;
        }
      }
    }

    &.mdc-text-field--with-internal-counter {
      .mdc-text-field__input {
        // Space between textarea and internal counter should not be affected
        @include _textarea-input-with-internal-counter($query);
      }
    }
  }
}

///
/// Sets density scale for outlined textarea.
///
/// @param {Number | String} $density-scale - Density scale value for component. Supported density scale values `-4`,
///     `-3`, `-2`, `-1`, `0`. Default is `0`.
///
@mixin outlined-textarea-density(
  $density-scale,
  $query: feature-targeting.all()
) {
  $feat-structure: feature-targeting.create-target($query, structure);
  $keyframe-suffix: text-field-outlined-#{$density-scale};
  $label-top: density-functions.prop-value(
    $density-config: variables.$textarea-outlined-label-density-config,
    $density-scale: math.div($density-scale, 2),
    $property-name: top,
  );
  $textfield-height: density-functions.prop-value(
    $density-config: $_density-config,
    $density-scale: $density-scale,
    $property-name: height,
  );
  $margin-top: density-functions.prop-value(
    $density-config: variables.$textarea-outlined-density-config,
    $density-scale: math.div($density-scale, 2),
    $property-name: margin-top,
  );
  $margin-bottom: density-functions.prop-value(
    $density-config: variables.$textarea-outlined-density-config,
    $density-scale: math.div($density-scale, 2),
    $property-name: margin-bottom,
  );

  // Textarea mixins require two modifier classes since two are used internally
  // for styles (textarea and outlined). An extra class is added for the public
  // mixin so that only a single public class is needed for specificity.
  &.mdc-text-field--outlined {
    // Adjust the floating position and animation/keyframes of the floating
    // label by the new position of the resting label
    $label-top-difference: variables.$textarea-outlined-label-top - $label-top;

    // Floating label position
    @include notched-outline-mixins.floating-label-float-position-absolute(
      variables.$textarea-outlined-label-position-y - $label-top-difference,
      $query: $query
    );

    // Floating label animation
    @include floating-label-mixins.shake-animation(
      $keyframe-suffix,
      $query: $query
    );
    @at-root {
      @include floating-label-mixins.shake-keyframes(
        $keyframe-suffix,
        variables.$textarea-outlined-label-position-y - $label-top-difference,
        0%,
        $query: $query
      );
    }

    // Resting label position
    .mdc-floating-label {
      @include feature-targeting.targets($feat-structure) {
        top: $label-top;
      }
    }

    .mdc-text-field__resizer {
      @include feature-targeting.targets($feat-structure) {
        min-height: $textfield-height;
      }
    }

    .mdc-text-field__input {
      @include feature-targeting.targets($feat-structure) {
        margin-top: $margin-top;
        margin-bottom: $margin-bottom;
      }
    }

    &.mdc-text-field--with-internal-counter {
      .mdc-text-field__input {
        // Space between textarea and internal counter should not be affected
        @include _textarea-input-with-internal-counter($query);
      }
    }
  }
}

///
/// Sets the minimum number of rows for a textarea a textarea may be resized to.
///
/// For IE11 this mixin can be used instead of the rows attribute.
///
/// @param {Number} $rows - The minimum number of rows for a textarea.
/// @param {Number} $line-height - The line-height of the textarea.
///
@mixin textarea-min-rows(
  $rows,
  $line-height: variables.$textarea-line-height,
  $query: feature-targeting.all()
) {
  $feat-structure: feature-targeting.create-target($query, structure);

  .mdc-text-field__input {
    @include feature-targeting.targets($feat-structure) {
      min-height: $rows * $line-height;
    }
  }
}

///
/// Sets height of default text field variant.
///
/// @param {Number} $height
/// @param {Number} $minimum-height-for-filled-label Sets the minimum height for
///     filled textfields at which to allow floating labels.
/// @access public
///
@mixin height(
  $height,
  $minimum-height-for-filled-label: variables.$minimum-height-for-filled-label,
  $query: feature-targeting.all()
) {
  $feat-structure: feature-targeting.create-target($query, structure);
  @include feature-targeting.targets($feat-structure) {
    @include theme.property(height, $height);
  }

  // We can only hide the label (when there's not enough vertical space for it)
  // if we know the container height at compilation time.
  // That's not the case when $height is a custom property.
  @if not custom-properties.is-custom-prop($height) {
    @if $height < $minimum-height-for-filled-label {
      @include filled-no-label($query: $query);
    }
  }
}

///
/// Sets height of outlined text field variant (Excluding outlined text field with leading icon).
///
/// @param {Number} $height
/// @param {String} $keyframe-suffix - Optional suffix to use for generated
///     floating label keyframes
/// @param {Number} label-font-size - font size for the floating label. Defaults to 1rem.
/// @access public
///
@mixin outlined-height(
  $height,
  $keyframe-suffix: text-field-outlined-#{$height},
  $label-font-size: 1rem,
  $query: feature-targeting.all()
) {
  $feat-structure: feature-targeting.create-target($query, structure);
  $positionY: variables.get-outlined-label-position-y($height);

  // Floating label position
  @include notched-outline-mixins.floating-label-float-position-absolute(
    $positionY,
    $font-size: $label-font-size,
    $query: $query
  );

  // Floating label animation
  @include floating-label-mixins.shake-animation(
    $keyframe-suffix,
    $query: $query
  );
  @at-root {
    @include floating-label-mixins.shake-keyframes(
      $keyframe-suffix,
      $positionY,
      $query: $query
    );
  }

  @include feature-targeting.targets($feat-structure) {
    height: $height;
  }
}

///
/// Sets height of outlined text field with leading icon variant.
///
/// @param {Number} $height
/// @param {String} $keyframe-suffix - Optional suffix to use for generated
///     floating label keyframes
/// @param {Number} $label-font-size - Font-size for the textfield's floating label. It is necessary tto specify this value to ensure that the notched outline does not cut-off the label when floated, see b/302340517 for more info.
/// @access public
///
@mixin outlined-with-leading-icon-height(
  $height,
  $keyframe-suffix: null,
  $label-font-size: 1rem,
  $query: feature-targeting.all()
) {
  $feat-structure: feature-targeting.create-target($query, structure);

  // This extra specificity is needed because textfield applies the below mixin
  // already to two selectors (outlined + with-leading-icon). To override
  // them with a new label position and animation, another selector is needed.
  &.mdc-text-field--outlined {
    @include _outlined-with-leading-icon-floating-label-position-animation(
      $height,
      $keyframe-suffix,
      $label-font-size,
      $query
    );
  }

  @include feature-targeting.targets($feat-structure) {
    height: $height;
  }
}

// Mixin that sets the floating label position and animations for a given height.
// This mixin is separate to allow outlined-with-leading-icon-height() to
// provide greater specificity over the default mixin that adds styles for
// outlined with leading icons.
@mixin _outlined-with-leading-icon-floating-label-position-animation(
  $height,
  $keyframe-suffix: text-field-outlined-with-leading-icon-#{$height},
  $font-size: 1rem,
  $query: feature-targeting.all()
) {
  $positionY: variables.get-outlined-label-position-y($height);

  // Floating label position
  @include notched-outline-mixins.floating-label-float-position-absolute(
    $positionY,
    variables.$outlined-with-leading-icon-label-position-x,
    $font-size: $font-size,
    $query: $query
  );

  // Floating label animation
  @include floating-label-mixins.shake-animation(
    $keyframe-suffix,
    $query: $query
  );
  @at-root {
    @include floating-label-mixins.shake-keyframes(
      $keyframe-suffix,
      $positionY,
      variables.$outlined-with-leading-icon-label-position-x,
      $query: $query
    );
  }

  $keyframe-suffix-rtl: #{$keyframe-suffix}-rtl;
  @include rtl.rtl {
    @include floating-label-mixins.shake-animation(
      $keyframe-suffix,
      $query: $query
    );
  }
  @at-root {
    @include floating-label-mixins.shake-keyframes(
      $keyframe-suffix-rtl,
      $positionY,
      -(variables.$outlined-with-leading-icon-label-position-x),
      $query: $query
    );
  }
}

///
/// Sets shape radius of default text field variant.
///
/// @param {Number} $radius Shape radius value in `px` or in percentage.
/// @param {Number} $text-field-height Height of default text field variant. Required only when `$radius` is in
///     percentage unit and if text field has custom height. Defaults to `variables.$height`.
/// @param {Boolean} $rtl-reflexive Set to true to flip shape radius in RTL context. Defaults to `false`.
///
@mixin shape-radius(
  $radius,
  $density-scale: variables.$density-scale,
  $rtl-reflexive: false,
  $query: feature-targeting.all()
) {
  @if (meta.type-of($radius) == 'list') and
    (list.length($radius) > 2) and
    (list.nth($radius, 3) != 0 or list.nth($radius, 4) != 0)
  {
    @error "mdc-textfield: Invalid radius #{$radius}. Only top-left and top-right corners may be customized.";
  }

  $height: density-functions.prop-value(
    $density-config: $_density-config,
    $density-scale: $density-scale,
    $property-name: height,
  );

  $masked-radius: shape-functions.mask-radius($radius, 1 1 0 0);

  $fallback: if(
    custom-properties.is-custom-prop($radius),
    custom-properties.get-fallback($radius),
    null
  );

  @if meta.type-of($fallback) == 'list' {
    $fallback: css.unpack-value($fallback);
    $first: list.nth($masked-radius, 1);
    $second: list.nth($masked-radius, 2);
    $third: list.nth($masked-radius, 3);
    $fourth: list.nth($masked-radius, 4);
    $masked-radius: (
      if(
        custom-properties.is-custom-prop($first),
        custom-properties.set-fallback($first, list.nth($fallback, 1)),
        $first
      ),
      if(
        custom-properties.is-custom-prop($second),
        custom-properties.set-fallback($second, list.nth($fallback, 2)),
        $second
      ),
      if(
        custom-properties.is-custom-prop($third),
        custom-properties.set-fallback($third, list.nth($fallback, 3)),
        $third
      ),
      if(
        custom-properties.is-custom-prop($fourth),
        custom-properties.set-fallback($fourth, list.nth($fallback, 4)),
        $fourth
      )
    );
  }

  @include shape-mixins.radius(
    $masked-radius,
    $rtl-reflexive,
    $component-height: $height,
    $query: $query
  );
}

@mixin textarea-shape-radius(
  $radius,
  $rtl-reflexive: false,
  $query: feature-targeting.all()
) {
  @include notched-outline-mixins.shape-radius(
    $radius,
    $rtl-reflexive,
    $query: $query
  );
}

///
/// Customizes the color of the text entered into an enabled text field.
/// @param {Color} $color - The desired input text color.
///
@mixin ink-color($color, $query: feature-targeting.all()) {
  @include if-enabled_ {
    @include ink-color_($color, $query: $query);
  }
}

///
/// Customizes the color of the entered text in a disabled text field.
/// @param {Color} $color - The desired input text color.
///
@mixin disabled-ink-color($color, $query: feature-targeting.all()) {
  @include if-disabled_ {
    @include ink-color_($color, $query: $query);
  }
}

///
/// Customizes the color of the placeholder in an enabled text field.
/// @param {Color} $color - The desired placeholder text color.
///
@mixin placeholder-color($color, $query: feature-targeting.all()) {
  @include if-enabled_ {
    @include placeholder-color_($color, $query: $query);
  }
}

///
/// Customizes the color of the placeholder in a disabled text field.
/// @param {Color} $color - The desired placeholder text color.
///
@mixin disabled-placeholder-color($color, $query: feature-targeting.all()) {
  @include if-disabled_ {
    @include placeholder-color_($color, $query: $query);
  }
}

///
/// Customizes the background color of the text field or textarea when enabled.
/// @param {Color} $color - The desired background color.
///
@mixin fill-color($color, $query: feature-targeting.all()) {
  @include if-enabled_ {
    @include fill-color_($color, $query: $query);
  }
}

///
/// Customizes the background color of the text field or textarea when disabled.
/// @param {Color} $color - The desired background color.
///
@mixin disabled-fill-color($color, $query: feature-targeting.all()) {
  @include if-disabled_ {
    @include fill-color_($color, $query: $query);
  }
}

///
/// Customizes the text field bottom line color for the filled variant.
/// @param {Color} $color - The desired bottom line color.
///
@mixin bottom-line-color($color, $query: feature-targeting.all()) {
  @include if-enabled_ {
    @include bottom-line-color_($color, $query: $query);
  }
}

///
/// Customizes the disabled text field bottom line color for the filled variant.
/// @param {Color} $color - The desired bottom line color.
///
@mixin disabled-bottom-line-color($color, $query: feature-targeting.all()) {
  @include if-disabled_ {
    @include bottom-line-color_($color, $query: $query);
  }
}

///
/// Customizes the hover text field bottom line color for the filled variant.
/// @param {Color} $color - The desired bottom line color.
///
@mixin hover-bottom-line-color($color, $query: feature-targeting.all()) {
  @include if-enabled_ {
    @include hover-bottom-line-color_($color, $query: $query);
  }
}

///
/// Customizes the color of the default line ripple of the text field.
/// @param {Color} $color - The desired line ripple color.
///
@mixin line-ripple-color($color, $query: feature-targeting.all()) {
  @include if-enabled_ {
    @include line-ripple-color_($color, $query: $query);
  }
}

///
/// Customizes the text color of the label in an enabled text field.
/// @param {Color} $color - The desired label text color.
///
@mixin label-color($color, $query: feature-targeting.all()) {
  @include if-enabled_ {
    @include label-ink-color_($color, $query: $query);
  }
}

///
/// Customizes the text color of the label in a disabled text field.
/// @param {Color} $color - The desired label text color.
///
@mixin disabled-label-color($color, $query: feature-targeting.all()) {
  @include if-disabled_ {
    @include label-ink-color_($color, $query: $query);
  }
}

///
/// Customizes the border color of the outlined text field or textarea.
/// @param {Color} $color - The desired outline border color.
///
@mixin outline-color($color, $query: feature-targeting.all()) {
  @include if-enabled_ {
    @include notched-outline-mixins.color($color, $query: $query);
  }
}

///
/// Customizes the outline border color when the text field or textarea is hovered.
/// @param {Color} $color - The desired outline border color.
///
@mixin hover-outline-color($color, $query: feature-targeting.all()) {
  @include if-enabled_ {
    @include hover-outline-color_($color, $query: $query);
  }
}

///
/// Customizes the outline border color when the text field or textarea is focused.
/// @param {Color} $color - The desired outline border color.
///
@mixin focused-outline-color($color, $query: feature-targeting.all()) {
  @include if-enabled_ {
    @include focused-outline-color_($color, $query: $query);
  }
}

///
/// Customizes the outline border color when the text field or textarea is disabled.
/// @param {Color} $color - The desired outline border color.
///
@mixin disabled-outline-color($color, $query: feature-targeting.all()) {
  @include if-disabled_ {
    @include notched-outline-mixins.color($color, $query: $query);
  }
}

///
/// Customizes the caret color of the text field or textarea.
/// @param {Color} $color - The desired caret color.
///
@mixin caret-color($color, $query: feature-targeting.all()) {
  $feat-color: feature-targeting.create-target($query, color);

  .mdc-text-field__input {
    @include feature-targeting.targets($feat-color) {
      @include theme.property(caret-color, $color);
    }
  }
}

///
/// Customizes the color of the prefix text for an enabled text field.
/// @param {Color} $color - The desired prefix text color.
///
@mixin prefix-color($color, $query: feature-targeting.all()) {
  @include if-enabled_ {
    @include _prefix-color($color, $query: $query);
  }
}

///
/// Customizes the color of the prefix text for a disabled text field.
/// @param {Color} $color - The desired prefix text color.
///
@mixin disabled-prefix-color($color, $query: feature-targeting.all()) {
  @include if-disabled_ {
    @include _prefix-color($color, $query: $query);
  }
}

///
/// Customizes the color of the suffix text for an enabled text field.
/// @param {Color} $color - The desired suffix text color.
///
@mixin suffix-color($color, $query: feature-targeting.all()) {
  @include if-enabled_ {
    @include _suffix-color($color, $query: $query);
  }
}

///
/// Customizes the color of the suffix text for a disabled text field.
/// @param {Color} $color - The desired suffix text color.
///
@mixin disabled-suffix-color($color, $query: feature-targeting.all()) {
  @include if-disabled_ {
    @include _suffix-color($color, $query: $query);
  }
}

///
/// Sets shape radius of outlined text field variant.
///
/// @param {Number} $radius Shape radius value in `px` or in percentage.
/// @param {Number} $text-field-height Height of outlined text field variant. Required only when `$radius` is in
///     percentage unit and if text field has custom height. Defaults to `variables.$height`.
/// @param {Boolean} $rtl-reflexive Set to true to flip shape radius in RTL context. Defaults to `false`.
///
@mixin outline-shape-radius(
  $radius,
  $density-scale: variables.$density-scale,
  $rtl-reflexive: false,
  $query: feature-targeting.all()
) {
  $feat-structure: feature-targeting.create-target($query, structure);
  $height: density-functions.prop-value(
    $density-config: $_density-config,
    $density-scale: $density-scale,
    $property-name: height,
  );

  .mdc-notched-outline {
    @include notched-outline-mixins.shape-radius(
      $radius,
      $rtl-reflexive,
      $component-height: $height,
      $query: $query
    );
  }

  $resolved-radius: shape-functions.resolve-radius(
    $radius,
    $component-height: $height
  );
  $unpacked-radius: shape-functions.unpack-radius($resolved-radius);
  $top-left-radius: list.nth($unpacked-radius, 1);
  $top-left-is-custom-prop: custom-properties.is-custom-prop($top-left-radius);
  $top-left-radius-px: $top-left-radius;
  @if ($top-left-is-custom-prop) {
    $top-left-radius-px: custom-properties.get-fallback($top-left-radius);
  }
  $top-right-radius: list.nth($unpacked-radius, 2);
  $top-right-is-custom-prop: custom-properties.is-custom-prop(
    $top-right-radius
  );

  @if (
    $top-left-is-custom-prop or
      $top-right-is-custom-prop or
      $top-left-radius-px >
      notched-outline-variables.$leading-width
  ) {
    // The horizontal padding only needs to be overriden from the base padding
    // if the radius is a custom property, or if the top-left radius is a value
    // that is large than that default notched outline's leading width.
    @include _outline-shape-radius-horizontal-padding(
      $top-left-radius,
      $top-right-radius,
      $query: $query
    );

    + .mdc-text-field-helper-line {
      @include _outline-shape-radius-horizontal-padding(
        $top-left-radius,
        $top-right-radius,
        $query: $query
      );
    }

    // Ensure that leading/trailing icon padding is overriden. Even if the
    // top left/right isn't a custom property or the leading isn't larger, we
    // still need to override. The above left/right padding rules have more
    // specificty than the original leading/trailing icon rules, so we need to
    // re-apply them.
    // Additionally, if the top left/right radii _are_ custom properties, we
    // should use those instead.

    &.mdc-text-field--with-leading-icon {
      @if ($top-right-is-custom-prop) {
        @include feature-targeting.targets($feat-structure) {
          @include rtl.ignore-next-line();
          padding-left: 0;
        }
        @include _apply-outline-shape-padding(
          padding-right,
          $top-right-radius,
          $query: $query
        );

        @include rtl.rtl {
          @include _apply-outline-shape-padding(
            padding-left,
            $top-right-radius,
            $query: $query
          );
          @include feature-targeting.targets($feat-structure) {
            @include rtl.ignore-next-line();
            padding-right: 0;
          }
        }
      } @else {
        @include _padding-horizontal-with-leading-icon($query);
      }
    }

    &.mdc-text-field--with-trailing-icon {
      @if (
        $top-left-is-custom-prop or
          $top-left-radius-px >
          notched-outline-variables.$leading-width
      ) {
        @include _apply-outline-shape-padding(
          padding-left,
          $top-left-radius,
          $add-label-padding: true,
          $query: $query
        );
        @include feature-targeting.targets($feat-structure) {
          @include rtl.ignore-next-line();
          padding-right: 0;
        }

        @include rtl.rtl {
          @include feature-targeting.targets($feat-structure) {
            @include rtl.ignore-next-line();
            padding-left: 0;
          }
          @include _apply-outline-shape-padding(
            padding-right,
            $top-left-radius,
            $add-label-padding: true,
            $query: $query
          );
        }
      } @else {
        @include _padding-horizontal-with-trailing-icon($query);
      }
    }

    &.mdc-text-field--with-leading-icon.mdc-text-field--with-trailing-icon {
      @include _padding-horizontal-with-both-icons($query);
    }
  }
}

@mixin _outline-shape-radius-horizontal-padding(
  $top-left-radius,
  $top-right-radius,
  $query: feature-targeting.all()
) {
  @include _apply-outline-shape-padding(
    padding-left,
    $top-left-radius,
    $add-label-padding: true,
    $query: $query
  );
  @include _apply-outline-shape-padding(
    padding-right,
    $top-right-radius,
    $query: $query
  );

  $top-left-is-custom-prop: custom-properties.is-custom-prop($top-left-radius);
  $top-left-radius-px: $top-left-radius;
  @if ($top-left-is-custom-prop) {
    $top-left-radius-px: custom-properties.get-fallback($top-left-radius);
  }
  $top-right-is-custom-prop: custom-properties.is-custom-prop(
    $top-right-radius
  );
  $top-right-radius-px: $top-right-radius;
  @if ($top-right-is-custom-prop) {
    $top-right-radius-px: custom-properties.get-fallback($top-right-radius);
  }

  @if (
    (
        $top-left-is-custom-prop and
          $top-right-is-custom-prop and not
          custom-properties.are-equal($top-left-radius, $top-right-radius)
      ) or
      $top-left-radius-px !=
      $top-right-radius-px
  ) {
    // Normally base horizontal padding doesn't need RTL, but if the values
    // are different or they are two different custom properties, they need to
    // be reversed.
    @include rtl.rtl {
      @include _apply-outline-shape-padding(
        padding-right,
        $top-left-radius,
        $add-label-padding: true,
        $query: $query
      );
      @include _apply-outline-shape-padding(
        padding-left,
        $top-right-radius,
        $query: $query
      );
    }
  }
}

@mixin _apply-outline-shape-padding(
  $property,
  $padding,
  $add-label-padding: false,
  $query: feature-targeting.all()
) {
  $feat-structure: feature-targeting.create-target($query, structure);
  $padding-is-custom-prop: custom-properties.is-custom-prop($padding);
  $padding-px: $padding;
  @if ($padding-is-custom-prop) {
    $padding-px: custom-properties.get-fallback($padding);
  }

  @include feature-targeting.targets($feat-structure) {
    // The shape should only change the padding if the radius becomes greater
    // than the default padding. That means we need to add more padding.
    @if ($padding-px > variables.$padding-horizontal) {
      // Set a px value if it's greater. This is either the only value (if
      // we're given an exact value), or an IE11 fallback if we're given a
      // custom property and the fallback value is greater than the padding.
      $value: $padding-px;
      @if ($add-label-padding) {
        // If this is for the top-left leading, add the notched outline padding
        // to keep it aligned with the label
        $value: $padding-px + notched-outline-variables.$padding;
      }

      @include rtl.ignore-next-line();
      #{$property}: $value;
      @if ($padding-is-custom-prop) {
        // Add an alternate GSS tag b/c this was an IE11 fallback and we're
        // going to add another property with the var() value
        /* @alternate */
      }
    }
    @if ($padding-is-custom-prop) {
      // If it's a custom property, always add it since the value may change
      // to be greater than the padding at runtime, even if the fallback is
      // not currently greater than the default padding.
      $value: custom-properties.create-var($padding);
      @if ($add-label-padding) {
        $value: calc(#{$value} + #{notched-outline-variables.$padding});
      }

      // Interpolation is a workaround for sass/sass#3259.
      @supports (top: max(#{0%})) {
        // A max() function makes this runtime dynamic. The padding will be
        // whichever is greater: the default horizontal padding, or the calculated
        // custom property plus extra padding.
        @include rtl.ignore-next-line();
        #{$property}: max(#{variables.$padding-horizontal}, #{$value});
      }
    }
  }
}

///
/// Sets the CSS transition for the floating label's 'float' animation.
///
/// @param {Number} $duration-ms - Duration (in ms) of the animation.
/// @param {String} $timing-function - Optionally overrides the default animation timing function.
///
@mixin floating-label-float-transition(
  $duration-ms,
  $timing-function: null,
  $query: feature-targeting.all()
) {
  .mdc-floating-label {
    @include floating-label-mixins.float-transition(
      $duration-ms,
      $timing-function,
      $query: $query
    );
  }
}

///
/// Sets custom font size of the input.
///
/// @param {number} $font-size - Overrides the font size.
///
@mixin input-font-size($font-size, $query: feature-targeting.all()) {
  $feat-typography: feature-targeting.create-target($query, typography);

  .mdc-text-field__input,
  .mdc-text-field__affix--suffix,
  .mdc-text-field__affix--prefix {
    @include feature-targeting.targets($feat-typography) {
      font-size: $font-size;
    }
  }
}

///
/// Sets custom font family of the input.
///
/// @param {String} $font-family - Selected font family.
///
@mixin input-font-family($font-family, $query: feature-targeting.all()) {
  $feat-typography: feature-targeting.create-target($query, typography);

  .mdc-text-field__input {
    @include feature-targeting.targets($feat-typography) {
      font-family: $font-family;
    }
  }
}

// Private mixins

// Base shared styles
@mixin _base($query: feature-targeting.all()) {
  $feat-structure: feature-targeting.create-target($query, structure);

  // Shape
  @include shape-radius(variables.$shape-radius, $query: $query);

  // Colors
  @include label-color(variables.$label, $query: $query);
  @include ink-color(variables.$ink-color, $query: $query);
  @include placeholder-color(variables.$placeholder-ink-color, $query: $query);
  @include caret-color(primary, $query: $query);
  @include helper-text-mixins.helper-text-color(
    variables.$helper-text-color,
    $query: $query
  );
  @include character-counter-mixins.character-counter-color(
    variables.$helper-text-color,
    $query: $query
  );
  @include icon-mixins.leading-icon-color(
    variables.$icon-color,
    $query: $query
  );
  @include icon-mixins.trailing-icon-color(
    variables.$icon-color,
    $query: $query
  );
  @include prefix-color(variables.$affix-color, $query: $query);
  @include suffix-color(variables.$affix-color, $query: $query);

  // Floating Label
  @include floating-label_($query);

  @include feature-targeting.targets($feat-structure) {
    // display and align-items are necessary to make the text field participate
    // in baseline alignment, even though some variants are 'centered'. Those
    // variants should use the _baseline-center-aligned() mixin
    display: inline-flex;
    align-items: baseline;
    padding: 0 variables.$padding-horizontal;
    position: relative;
    box-sizing: border-box;
    overflow: hidden;
    /* @alternate */
    will-change: opacity, transform, color;
  }
}

// This mixin adds styles to visually center the text within the text field.
// Sibling text will align to the baseline and appear centered next to the
// text field.
@mixin _baseline-center-aligned($query: feature-targeting.all()) {
  $feat-structure: feature-targeting.create-target($query, structure);

  @include feature-targeting.targets($feat-structure) {
    // In order for a flexbox container to participate in baseline alignment,
    // it follows these rules to determine where its baseline is:
    // https://www.w3.org/TR/css-flexbox-1/#flex-baselines
    //
    // In order to avoid leading icons 'controlling' the baseline (since they
    // are the first child), flexbox will generate a baseline from any child
    // flex items that participate in baseline alignment.
    //
    // Icons are set to "align-self: center", while all other children are
    // aligned to baseline. The next problem is deciding which child is
    // used to determine the baseline.
    //
    // According to spec, the item with the largest distance between its
    // baseline and the edge of the cross axis is placed flush with that edge,
    // making it the baseline of the container.
    // https://www.w3.org/TR/css-flexbox-1/#baseline-participation
    //
    // For the filled variant, the pseudo ::before strut is the 'largest'
    // child since the input has a height of 28px and the strut is 40px. We
    // can emulate center alignment and force the baseline to use the input
    // text by making the input the full height of the container and removing
    // the baseline strut.

    // IE11 does not respect this, and makes the leading icon (if present) the
    // baseline. This is a gap with IE11 that we have accepted.
    .mdc-text-field__input {
      height: 100%;
    }
  }
}

@mixin _padding-horizontal-with-leading-icon($query: feature-targeting.all()) {
  $feat-structure: feature-targeting.create-target($query, structure);

  @include feature-targeting.targets($feat-structure) {
    @include rtl.reflexive-property(padding, 0, variables.$padding-horizontal);
  }
}

@mixin _padding-horizontal-with-trailing-icon($query: feature-targeting.all()) {
  $feat-structure: feature-targeting.create-target($query, structure);

  @include feature-targeting.targets($feat-structure) {
    @include rtl.reflexive-property(padding, variables.$padding-horizontal, 0);
  }
}

@mixin _padding-horizontal-with-both-icons($query: feature-targeting.all()) {
  $feat-structure: feature-targeting.create-target($query, structure);

  @include feature-targeting.targets($feat-structure) {
    @include rtl.ignore-next-line();
    padding-left: 0;
    @include rtl.ignore-next-line();
    padding-right: 0;
  }
}

@mixin floating-label_($query: feature-targeting.all()) {
  $feat-structure: feature-targeting.create-target($query, structure);

  .mdc-floating-label {
    @include feature-targeting.targets($feat-structure) {
      top: 50%;
      transform: translateY(-50%);
      pointer-events: none;
    }
  }
}

// Filled

@mixin _filled($query: feature-targeting.all()) {
  // Text Field intentionally omits press ripple, so each state needs to be specified individually.
  @include ripple-theme.states-base-color(
    variables.$ink-color,
    $query: $query,
    $ripple-target: variables.$ripple-target
  );
  @include ripple-theme.states-hover-opacity(
    ripple-theme.states-opacity(variables.$ink-color, hover),
    $query: $query,
    $ripple-target: variables.$ripple-target
  );
  @include ripple-theme.states-focus-opacity(
    ripple-theme.states-opacity(variables.$ink-color, focus),
    $query: $query,
    $ripple-target: variables.$ripple-target
  );

  @include height(variables.$height, $query: $query);
  @include typography.baseline-top(
    variables.$filled-baseline-top,
    $query: $query
  );
  @include fill-color(variables.$background, $query: $query);
  @include bottom-line-color(variables.$bottom-line-idle, $query: $query);
  @include hover-bottom-line-color(
    variables.$bottom-line-hover,
    $query: $query
  );
  @include line-ripple-color_(primary, $query: $query);
  @include _filled-floating-label($query);
}

@mixin _filled-floating-label($query: feature-targeting.all()) {
  $feat-structure: feature-targeting.create-target($query, structure);

  .mdc-floating-label {
    @include feature-targeting.targets($feat-structure) {
      @include rtl.reflexive-position(left, variables.$label-offset);
    }
  }

  @include floating-label-mixins.float-position(
    variables.$label-position-y,
    $query: $query
  );
}

// Filled variant with no label. This variant centers the text elements and
// hides the label and is used with there is explicitly no label provided or
// when the height of the text field is too small for a label to be allowed.
@mixin filled-no-label($query: feature-targeting.all()) {
  $feat-structure: feature-targeting.create-target($query, structure);

  @include _baseline-center-aligned($query);
  @include feature-targeting.targets($feat-structure) {
    .mdc-floating-label {
      display: none;
    }

    &::before {
      // Remove baseline-top strut
      display: none;
    }
  }

  // Safari only
  @supports (-webkit-hyphens: none) {
    .mdc-text-field__affix {
      @include _centered-affix-safari-support($query: $query);
    }
  }
}

// Outlined

@mixin outlined_($query: feature-targeting.all()) {
  $feat-structure: feature-targeting.create-target($query, structure);

  @include outlined-height(
    $height: variables.$height,
    $keyframe-suffix: text-field-outlined,
    $query: $query
  );
  @include _baseline-center-aligned($query: $query);
  @include outline-color(variables.$outlined-idle-border, $query: $query);
  @include hover-outline-color(
    variables.$outlined-hover-border,
    $query: $query
  );
  @include focused-outline-color(primary, $query: $query);
  @include outline-shape-radius(variables.$shape-radius, $query: $query);
  @include notched-outline-mixins.notch-offset(
    notched-outline-variables.$border-width,
    $query: $query
  );
  @include ripple-theme.states-base-color(
    transparent,
    $query: $query,
    $ripple-target: variables.$ripple-target
  );
  @include _outlined-floating-label($query);

  @include feature-targeting.targets($feat-structure) {
    overflow: visible;
  }

  .mdc-text-field__input {
    @include feature-targeting.targets($feat-structure) {
      // TODO(b/154349735): Investigate the neccessity of these styles
      display: flex;
      // stylelint-disable-next-line declaration-no-important --
      // FF adds unwanted border in HC mode on windows.
      border: none !important;
      background-color: transparent;
    }
  }
}

@mixin _outlined-floating-label($query: feature-targeting.all()) {
  $feat-structure: feature-targeting.create-target($query, structure);

  .mdc-floating-label {
    @include feature-targeting.targets($feat-structure) {
      @include rtl.reflexive-position(left, notched-outline-variables.$padding);
    }
  }
}

@mixin _outlined-notched-outline($query: feature-targeting.all()) {
  $feat-structure: feature-targeting.create-target($query, structure);

  @include feature-targeting.targets($feat-structure) {
    // Force the outline to appear "above" the textfield elements, even though
    // it is absolutely positioned and comes before the input in the DOM. This
    // is primarily for the textarea scrollbar and resize elements, which may
    // clip with with outline border.
    z-index: 1;
  }
}

// States

@mixin disabled_($query: feature-targeting.all()) {
  $feat-structure: feature-targeting.create-target($query, structure);

  @include ink-color_(variables.$disabled-ink-color, $query: $query);
  @include placeholder-color_(
    variables.$disabled-placeholder-ink-color,
    $query: $query
  );
  @include label-ink-color_(variables.$disabled-label-color, $query: $query);
  @include helper-text-mixins.helper-text-color_(
    variables.$disabled-helper-text-color,
    $query: $query
  );
  @include character-counter-mixins.character-counter-color_(
    variables.$disabled-helper-text-color,
    $query: $query
  );
  @include icon-mixins.leading-icon-color_(
    variables.$disabled-icon,
    $query: $query
  );
  @include icon-mixins.trailing-icon-color_(
    variables.$disabled-icon,
    $query: $query
  );
  @include _prefix-color(variables.$disabled-affix-color, $query: $query);
  @include _suffix-color(variables.$disabled-affix-color, $query: $query);

  // Mixins that are ok to include since they target variant-specific elements
  @include bottom-line-color_(variables.$disabled-border, $query: $query);
  @include notched-outline-mixins.color(
    variables.$outlined-disabled-border,
    $query: $query
  );

  @include dom.forced-colors-mode {
    @include placeholder-color_(GrayText, $query: $query);
    @include label-ink-color_(GrayText, $query: $query);
    @include helper-text-mixins.helper-text-color_(GrayText, $query: $query);
    @include character-counter-mixins.character-counter-color_(
      GrayText,
      $query: $query
    );
    @include icon-mixins.leading-icon-color_(GrayText, $query: $query);
    @include icon-mixins.trailing-icon-color_(GrayText, $query: $query);
    @include _prefix-color(GrayText, $query: $query);
    @include _suffix-color(GrayText, $query: $query);

    // Mixins that are ok to include since they target variant-specific elements
    @include bottom-line-color_(GrayText, $query: $query);
    @include notched-outline-mixins.color(GrayText, $query: $query);
  }

  @include dom.forced-colors-mode($exclude-ie11: true) {
    .mdc-text-field__input {
      @include feature-targeting.targets($feat-structure) {
        background-color: Window;
      }
    }

    .mdc-floating-label {
      @include feature-targeting.targets($feat-structure) {
        z-index: 1;
      }
    }
  }

  @include feature-targeting.targets($feat-structure) {
    pointer-events: none;
  }

  .mdc-floating-label {
    @include feature-targeting.targets($feat-structure) {
      cursor: default;
    }
  }
}

@mixin _disabled-input($query: feature-targeting.all()) {
  $feat-structure: feature-targeting.create-target($query, structure);

  @include feature-targeting.targets($feat-structure) {
    // disabled inputs should still allow users to interact with them to select
    // text and scroll for textareas
    pointer-events: auto;
  }
}

@mixin _disabled-filled($query: feature-targeting.all()) {
  $feat-structure: feature-targeting.create-target($query, structure);

  @include fill-color_(variables.$disabled-background, $query: $query);

  #{variables.$ripple-target} {
    @include feature-targeting.targets($feat-structure) {
      // prevent ripple from displaying on hover when some interactible
      // elements like input and resize handles are hovered
      display: none;
    }
  }
}

@mixin invalid_($query: feature-targeting.all()) {
  $feat-structure: feature-targeting.create-target($query, structure);

  @include hover-bottom-line-color(variables.$error, $query: $query);
  @include line-ripple-color(variables.$error, $query: $query);
  @include label-color(variables.$error, $query: $query);
  @include helper-text-mixins.helper-text-validation-color(
    variables.$error,
    $query: $query
  );
  @include caret-color(variables.$error, $query: $query);
  @include icon-mixins.trailing-icon-color(variables.$error, $query: $query);

  // Mixins that are ok to include since they target variant-specific elements
  @include bottom-line-color(variables.$error, $query: $query);
  @include outline-color(variables.$error, $query: $query);
  @include hover-outline-color(variables.$error, $query: $query);
  @include focused-outline-color(variables.$error, $query: $query);

  + .mdc-text-field-helper-line .mdc-text-field-helper-text--validation-msg {
    @include feature-targeting.targets($feat-structure) {
      opacity: 1;
    }
  }
}

@mixin focused_($query: feature-targeting.all()) {
  $feat-structure: feature-targeting.create-target($query, structure);

  @include label-color(variables.$focused-label-color, $query: $query);

  // Mixins that are ok to include since they target variant-specific elements
  @include notched-outline-mixins.stroke-width(
    variables.$outlined-stroke-width,
    $query: $query
  );

  + .mdc-text-field-helper-line
    .mdc-text-field-helper-text:not(
      .mdc-text-field-helper-text--validation-msg
    ) {
    @include feature-targeting.targets($feat-structure) {
      opacity: 1;
    }
  }
}

@mixin _focused-outlined($query: feature-targeting.all()) {
  @include notched-outline-mixins.notch-offset(
    variables.$outlined-stroke-width,
    $query: $query
  );
}

@mixin _focused-outlined-textarea($query: feature-targeting.all()) {
  @include notched-outline-mixins.notch-offset(0, $query: $query);
}

// Icons

@mixin with-leading-icon_($query: feature-targeting.all()) {
  $feat-structure: feature-targeting.create-target($query, structure);

  $icon-padding: icon-variables.$leading-icon-padding-left +
    icon-variables.$icon-size + icon-variables.$leading-icon-padding-right;

  .mdc-floating-label {
    @include _truncate-floating-label-max-width($icon-padding, $query: $query);
    @include feature-targeting.targets($feat-structure) {
      @include rtl.reflexive-position(left, $icon-padding);
    }
  }

  $truncation: $icon-padding + variables.$padding-horizontal;

  .mdc-floating-label--float-above {
    @include _truncate-floating-label-floated-max-width(
      $truncation,
      $query: $query
    );
  }
}

@mixin _with-trailing-icon($query: feature-targeting.all()) {
  $truncation: icon-variables.$trailing-icon-padding-left +
    icon-variables.$icon-size + icon-variables.$trailing-icon-padding-right +
    variables.$label-offset;

  .mdc-floating-label {
    @include _truncate-floating-label-max-width($truncation, $query: $query);
  }

  .mdc-floating-label--float-above {
    @include _truncate-floating-label-floated-max-width(
      $truncation,
      $query: $query
    );
  }
}

@mixin _with-leading-and-trailing-icon($query: feature-targeting.all()) {
  $leading-icon: icon-variables.$leading-icon-padding-left +
    icon-variables.$icon-size + icon-variables.$leading-icon-padding-right;
  $trailing-icon: icon-variables.$trailing-icon-padding-left +
    icon-variables.$icon-size + icon-variables.$trailing-icon-padding-right;
  $truncation: $leading-icon + $trailing-icon;

  .mdc-floating-label {
    @include _truncate-floating-label-max-width($truncation, $query: $query);
  }

  .mdc-floating-label--float-above {
    @include _truncate-floating-label-floated-max-width(
      $truncation,
      $query: $query
    );
  }
}

@mixin outlined-with-leading-icon_($query: feature-targeting.all()) {
  $feat-structure: feature-targeting.create-target($query, structure);

  // Resting label position
  $icon-padding: icon-variables.$leading-icon-padding-left +
    icon-variables.$icon-size + icon-variables.$leading-icon-padding-right;
  $left-spacing: $icon-padding - notched-outline-variables.$leading-width;

  .mdc-floating-label {
    @include feature-targeting.targets($feat-structure) {
      @include rtl.reflexive-position(left, $left-spacing);
    }
  }

  // Notch width
  $notch-truncation: $icon-padding + notched-outline-variables.$leading-width;
  @include _truncate-notched-outline-max-width(
    $notch-truncation,
    $query: $query
  );

  // Floating label position and animation
  @include _outlined-with-leading-icon-floating-label-position-animation(
    $height: variables.$height,
    $keyframe-suffix: text-field-outlined-leading-icon,
    $query: $query
  );
}

///
/// Applied to the outlined text field with a trailing icon
///
@mixin _outlined-with-trailing-icon($query: feature-targeting.all()) {
  // Resting label position
  $icon-padding: icon-variables.$trailing-icon-padding-left +
    icon-variables.$icon-size + icon-variables.$trailing-icon-padding-right;
  // Notch width
  $notch-truncation: $icon-padding + notched-outline-variables.$leading-width;

  @include _truncate-notched-outline-max-width(
    $notch-truncation,
    $query: $query
  );
}

///
/// Truncates the max-width of the notched outline by the given amount
///
/// @param {Number} $truncation - Amount to truncate the notched outline max-width
///
@mixin _truncate-notched-outline-max-width(
  $truncation,
  $query: feature-targeting.all()
) {
  @include notched-outline-mixins.notch-max-width(
    calc(100% - #{$truncation}),
    $query: $query
  );
}

///
/// Truncates the max-width of the floating label by the given amount
///
/// @param {Number} $truncation - Amount to truncate the floating label max-width
///
@mixin _truncate-floating-label-max-width(
  $truncation,
  $query: feature-targeting.all()
) {
  @include floating-label-mixins.max-width(
    calc(100% - #{$truncation}),
    $query: $query
  );
}

///
/// Truncates the max-width of the floating label by the given amount while scaling by the given scale value
///
/// @param {Number} $truncation - Amount to truncate the floating label max-width
///
@mixin _truncate-floating-label-floated-max-width(
  $truncation,
  $query: feature-targeting.all()
) {
  $scale: floating-label-variables.$float-scale;
  @include floating-label-mixins.max-width(
    calc(100% / #{$scale} - #{$truncation} / #{$scale}),
    $query: $query
  );
}

// Textarea

@mixin textarea_($query: feature-targeting.all()) {
  $feat-structure: feature-targeting.create-target($query, structure);
  $feat-animation: feature-targeting.create-target($query, animation);

  @include _textarea-floating-label($query);

  @include feature-targeting.targets($feat-structure) {
    flex-direction: column;
    align-items: center;
    width: auto;
    height: auto;
    padding: 0; // see below for explanation
  }

  @include feature-targeting.targets($feat-animation) {
    transition: none;
  }
}

@mixin _textarea-resizer($query: feature-targeting.all()) {
  $feat-structure: feature-targeting.create-target($query, structure);

  @include feature-targeting.targets($feat-structure) {
    align-self: stretch;
    display: inline-flex;
    flex-direction: column;
    flex-grow: 1;
    max-height: 100%;
    max-width: 100%;
    min-height: variables.$height;
    // 'stretch' is the preferred rule here. It will allow the textarea to grow
    // to the min/max width of the container, but if an explicit width is set,
    // it cannot be resized horizontally.
    // Stretch is still a working draft. Chrome and Firefox have it implemented
    // with 'available' prefixes. fit-content is another good target for
    // Safari since it works in almost all use cases except when an explicit
    // width is set (the user can make the textarea smaller than the container).
    // None of this matters for IE11, which doesn't support resize.
    min-width: fit-content;
    /* @alternate */
    min-width: -moz-available;
    /* @alternate */
    min-width: -webkit-fill-available;
    overflow: hidden;
    resize: both;
  }
}

@mixin _textarea-filled-resizer($query: feature-targeting.all()) {
  $feat-structure: feature-targeting.create-target($query, structure);
  // Shift the resizer element up by a margin amount to make space for the
  // resize handle. For filled elements, the resize handle directly touches
  // the bottom line and is hard to see.
  // Using a margin affects the width and positioning of the overall component
  // and underlying textarea, which is why a transform is used instead.
  $y: -1 * variables.$textarea-input-handle-margin;

  @include feature-targeting.targets($feat-structure) {
    transform: translateY($y);
  }
}

@mixin _textarea-filled-resizer-children($query: feature-targeting.all()) {
  $feat-structure: feature-targeting.create-target($query, structure);
  // See above. After shifting the resize wrapper element, all of its children
  // should be shifted in the opposite direction (down) to compensate.
  $y: variables.$textarea-input-handle-margin;

  @include feature-targeting.targets($feat-structure) {
    transform: translateY($y);
  }
}

@mixin _textarea-outlined-resizer($query: feature-targeting.all()) {
  $feat-structure: feature-targeting.create-target($query, structure);
  // Shift the resizer element left/up by a margin amount to make space for the
  // resize handle. For outlined elements, the resize handle directly touches
  // the outline and is hard to see.
  // Using a margin affects the width and positioning of the overall component
  // and underlying textarea, which is why a transform is used instead.
  $x: -1 * variables.$textarea-input-handle-margin;
  $y: -1 * variables.$textarea-input-handle-margin;

  @include feature-targeting.targets($feat-structure) {
    @include rtl.ignore-next-line();
    transform: translateX($x) translateY($y);

    @include rtl.rtl {
      // Flip the horizontal shifting direction for RTL
      @include rtl.ignore-next-line();
      transform: translateX(-1 * $x) translateY($y);
    }
  }
}

@mixin _textarea-outlined-resizer-children($query: feature-targeting.all()) {
  $feat-structure: feature-targeting.create-target($query, structure);
  // See above. After shifting the resize wrapper element, all of its children
  // should be shifted in the opposite direction (right and down) to compensate.
  $x: variables.$textarea-input-handle-margin;
  $y: variables.$textarea-input-handle-margin;

  @include feature-targeting.targets($feat-structure) {
    @include rtl.ignore-next-line();
    transform: translateX($x) translateY($y);

    @include rtl.rtl {
      // Flip the horizontal shifting direction for RTL
      @include rtl.ignore-next-line();
      transform: translateX(-1 * $x) translateY($y);
    }
  }
}

@mixin _textarea-floating-label($query: feature-targeting.all()) {
  $feat-structure: feature-targeting.create-target($query, structure);

  // Resting label position
  .mdc-floating-label {
    @include feature-targeting.targets($feat-structure) {
      top: variables.$textarea-label-top;
    }

    // Resets center aligning the floating label.
    &:not(.mdc-floating-label--float-above) {
      @include feature-targeting.targets($feat-structure) {
        transform: none;
      }
    }
  }
}

@mixin _textarea-input($query: feature-targeting.all()) {
  $feat-structure: feature-targeting.create-target($query, structure);
  $feat-typography: feature-targeting.create-target($query, typography);

  @include feature-targeting.targets($feat-structure) {
    flex-grow: 1;
    height: auto;
    min-height: variables.$textarea-line-height;
    overflow-x: hidden; // https://bugzilla.mozilla.org/show_bug.cgi?id=33654
    overflow-y: auto;
    box-sizing: border-box;
    resize: none;
    // Textarea has horizontal padding instead of the container. This allows the
    // resize handle to extend to the edge of the container.
    padding: 0 variables.$padding-horizontal;
  }

  @include feature-targeting.targets($feat-typography) {
    line-height: variables.$textarea-line-height;
  }
}

@mixin _textarea-internal-counter($query: feature-targeting.all()) {
  $feat-structure: feature-targeting.create-target($query, structure);

  @include typography.baseline-bottom(
    variables.$textarea-internal-counter-baseline-bottom,
    $query: $query
  );
  @include feature-targeting.targets($feat-structure) {
    align-self: flex-end;
    // Needed since padding is on the textarea and not the container
    padding: 0 variables.$padding-horizontal;

    &::before {
      // Remove baseline-top
      display: none;
    }
  }
}

@mixin _textarea-input-with-internal-counter($query: feature-targeting.all()) {
  $feat-structure: feature-targeting.create-target($query, structure);

  @include feature-targeting.targets($feat-structure) {
    margin-bottom: variables.$textarea-internal-counter-input-margin-bottom;
  }
}

@mixin _textarea-filled($query: feature-targeting.all()) {
  $feat-structure: feature-targeting.create-target($query, structure);

  @include feature-targeting.targets($feat-structure) {
    &::before {
      // <textarea> does not align to baseline when it does not have a value,
      // unlike <input>, so we have to use padding to fake it instead
      display: none;
    }
  }

  // Floating label position
  @include floating-label-mixins.float-position(
    variables.$textarea-filled-label-position-y,
    $query: $query
  );

  // Floating label animation
  @include floating-label-mixins.shake-animation(
    textarea-filled,
    $query: $query
  );
  @at-root {
    @include floating-label-mixins.shake-keyframes(
      textarea-filled,
      variables.$textarea-filled-label-position-y,
      0%,
      $query: $query
    );
  }
}

@mixin _textarea-filled-input($query: feature-targeting.all()) {
  $feat-structure: feature-targeting.create-target($query, structure);

  @include feature-targeting.targets($feat-structure) {
    margin-top: variables.$textarea-filled-input-margin-top;
    margin-bottom: variables.$textarea-filled-input-margin-bottom;
  }
}

@mixin _textarea-filled-no-label-input($query: feature-targeting.all()) {
  $feat-structure: feature-targeting.create-target($query, structure);

  @include feature-targeting.targets($feat-structure) {
    margin-top: variables.$textarea-filled-no-label-input-margin-top;
    margin-bottom: variables.$textarea-filled-no-label-input-margin-bottom;
  }
}

@mixin _textarea-outlined($query: feature-targeting.all()) {
  @include notched-outline-mixins.notch-offset(0, $query: $query);

  // Floating label position
  @include notched-outline-mixins.floating-label-float-position-absolute(
    variables.$textarea-outlined-label-position-y,
    $query: $query
  );

  // Floating label animation
  @include floating-label-mixins.shake-animation(
    textarea-outlined,
    $query: $query
  );
  @at-root {
    @include floating-label-mixins.shake-keyframes(
      textarea-outlined,
      variables.$textarea-outlined-label-position-y,
      0%,
      $query: $query
    );
  }
}

@mixin _textarea-outlined-floating-label($query: feature-targeting.all()) {
  $feat-structure: feature-targeting.create-target($query, structure);

  @include feature-targeting.targets($feat-structure) {
    top: variables.$textarea-outlined-label-top;
  }
}

@mixin _textarea-outlined-input($query: feature-targeting.all()) {
  $feat-structure: feature-targeting.create-target($query, structure);

  @include feature-targeting.targets($feat-structure) {
    margin-top: variables.$textarea-outlined-input-margin-top;
    margin-bottom: variables.$textarea-outlined-input-margin-bottom;
  }
}

// Text, Prefix and Suffix

// Common styles for the text of the text field, including the prefix, suffix,
// and input.
@mixin _text($query: feature-targeting.all()) {
  $feat-animation: feature-targeting.create-target($query, animation);
  $feat-structure: feature-targeting.create-target($query, structure);

  // Exclude setting line-height to keep caret (text cursor) same height as the input text in iOS browser.
  @include typography.typography(
    subtitle1,
    $exclude-props: (line-height),
    $query: $query
  );
  @include feature-targeting.targets($feat-structure) {
    height: variables.$input-height;
  }

  @include feature-targeting.targets($feat-animation) {
    transition: animation.standard(opacity, 150ms);
  }
}

@mixin _input($query: feature-targeting.all()) {
  $feat-structure: feature-targeting.create-target($query, structure);

  @include _text($query: $query);
  @include feature-targeting.targets($feat-structure) {
    width: 100%;
    min-width: 0; // Fixes flex issues on Firefox
    border: none;
    border-radius: 0;
    background: none;
    appearance: none;
    padding: 0;

    // Remove built-in trailing clear icon on IE11. IE vendor prefixes cannot
    // be combined with other vendor prefixes like the webkit one below.
    &::-ms-clear {
      display: none;
    }

    // Remove built-in datepicker icon on Chrome
    &::-webkit-calendar-picker-indicator {
      display: none;
    }

    &:focus {
      outline: none;
    }

    // Remove red outline on firefox
    &:invalid {
      box-shadow: none;
    }
  }
}

@mixin _input-placeholder($query: feature-targeting.all()) {
  $feat-animation: feature-targeting.create-target($query, animation);
  $feat-structure: feature-targeting.create-target($query, structure);

  @include feature-targeting.targets($feat-animation) {
    transition: animation.standard(opacity, 67ms);
  }

  @include feature-targeting.targets($feat-structure) {
    opacity: 0;
  }
}

@mixin _input-placeholder-visible($query: feature-targeting.all()) {
  $feat-animation: feature-targeting.create-target($query, animation);
  $feat-structure: feature-targeting.create-target($query, structure);

  @include feature-targeting.targets($feat-animation) {
    transition-delay: 40ms;
    transition-duration: 110ms;
  }

  @include feature-targeting.targets($feat-structure) {
    opacity: 1;
  }
}

@mixin _affix($query: feature-targeting.all()) {
  $feat-structure: feature-targeting.create-target($query, structure);

  @include _text($query: $query);
  @include feature-targeting.targets($feat-structure) {
    opacity: 0;
    white-space: nowrap;
  }
}

// TODO(b/155467610): Remove when Safari supports baseline alignment
// https://github.com/material-components/material-components-web/issues/5879
@mixin _centered-affix-safari-support($query: feature-targeting.all()) {
  $feat-structure: feature-targeting.create-target($query, structure);

  @include feature-targeting.targets($feat-structure) {
    align-items: center;
    align-self: center;
    display: inline-flex;
    height: 100%;
  }
}

@mixin _affix-visible($query: feature-targeting.all()) {
  $feat-structure: feature-targeting.create-target($query, structure);

  @include feature-targeting.targets($feat-structure) {
    opacity: 1;
  }
}

@mixin _prefix($query: feature-targeting.all()) {
  $feat-structure: feature-targeting.create-target($query, structure);

  @include feature-targeting.targets($feat-structure) {
    @include rtl.reflexive-box(padding, right, variables.$prefix-padding);
  }
}

@mixin _prefix-end-aligned($query: feature-targeting.all()) {
  $feat-structure: feature-targeting.create-target($query, structure);

  @include feature-targeting.targets($feat-structure) {
    @include rtl.reflexive-box(
      padding,
      right,
      variables.$prefix-end-aligned-padding
    );
  }
}

@mixin _suffix($query: feature-targeting.all()) {
  $feat-structure: feature-targeting.create-target($query, structure);

  @include feature-targeting.targets($feat-structure) {
    @include rtl.reflexive-box(padding, left, variables.$suffix-padding);
  }
}

@mixin _suffix-end-aligned($query: feature-targeting.all()) {
  $feat-structure: feature-targeting.create-target($query, structure);

  @include feature-targeting.targets($feat-structure) {
    @include rtl.reflexive-box(
      padding,
      left,
      variables.$suffix-end-aligned-padding
    );
  }
}

// End aligned
@mixin end-aligned_($query: feature-targeting.all()) {
  $feat-structure: feature-targeting.create-target($query, structure);

  .mdc-text-field__input {
    @include feature-targeting.targets($feat-structure) {
      // IE11 does not support text-align: end
      @include rtl.ignore-next-line();
      text-align: right;
    }

    @include rtl.rtl {
      @include feature-targeting.targets($feat-structure) {
        @include rtl.ignore-next-line();
        text-align: left;
      }
    }
  }
}

// Forces input, prefix, and suffix to be LTR when in an RTL environment. Other
// elements such as labels and icons will remain RTL.
@mixin _ltr-text($query: feature-targeting.all()) {
  $feat-structure: feature-targeting.create-target($query, structure);

  @include feature-targeting.targets($feat-structure) {
    @include rtl.rtl {
      .mdc-text-field__input,
      .mdc-text-field__affix {
        @include rtl.ignore-next-line();
        direction: ltr;
      }

      .mdc-text-field__affix--prefix {
        @include rtl.ignore-next-line();
        padding-left: 0;
        @include rtl.ignore-next-line();
        padding-right: variables.$prefix-padding;
      }

      .mdc-text-field__affix--suffix {
        @include rtl.ignore-next-line();
        padding-left: variables.$suffix-padding;
        @include rtl.ignore-next-line();
        padding-right: 0;
      }

      // Need to specify an order for all elements since icons maintain their
      // original positions. We can't just reverse the container.
      .mdc-text-field__icon--leading {
        order: 1;
      }

      .mdc-text-field__affix--suffix {
        order: 2;
      }

      .mdc-text-field__input {
        order: 3;
      }

      .mdc-text-field__affix--prefix {
        order: 4;
      }

      .mdc-text-field__icon--trailing {
        order: 5;
      }
    }
  }
}

// Forces input, prefix, and suffix that are already forced to LTR to also be
// end-aligned. This mixin should be used alongside the styles provided in
// _ltr-text().
@mixin _ltr-text-end-aligned($query: feature-targeting.all()) {
  $feat-structure: feature-targeting.create-target($query, structure);

  @include feature-targeting.targets($feat-structure) {
    @include rtl.rtl {
      .mdc-text-field__input {
        // IE11 does not support text-align: end, so we need to duplicate
        // the LTR end-aligned style here.
        @include rtl.ignore-next-line();
        text-align: right;
      }

      .mdc-text-field__affix--prefix {
        // padding-left: 0 provided by _ltr-text mixin
        @include rtl.ignore-next-line();
        padding-right: variables.$prefix-end-aligned-padding;
      }

      .mdc-text-field__affix--suffix {
        @include rtl.ignore-next-line();
        padding-left: variables.$suffix-end-aligned-padding;
        // padding-right: 0 provided by _ltr-text mixin
      }
    }
  }
}

// Customization

@mixin ink-color_($color, $query: feature-targeting.all()) {
  $feat-color: feature-targeting.create-target($query, color);

  .mdc-text-field__input {
    @include feature-targeting.targets($feat-color) {
      @include theme.property(color, $color);
    }
  }
}

@mixin placeholder-color_($color, $query: feature-targeting.all()) {
  $feat-color: feature-targeting.create-target($query, color);

  @include feature-targeting.targets($feat-color) {
    .mdc-text-field__input {
      @include placeholder-selector_ {
        @include theme.property(color, $color);
      }
    }
  }
}

@mixin fill-color_(
  $color,
  $query: feature-targeting.all(),
  $addAlternate: false
) {
  $feat-color: feature-targeting.create-target($query, color);

  @include feature-targeting.targets($feat-color) {
    @if ($addAlternate) {
      /* @alternate */
    }
    @include theme.property(background-color, $color);
  }
}

@mixin bottom-line-color_($color, $query: feature-targeting.all()) {
  .mdc-line-ripple {
    @include line-ripple-mixins.inactive-color($color, $query: $query);
  }
}

@mixin hover-bottom-line-color_($color, $query: feature-targeting.all()) {
  $feat-color: feature-targeting.create-target($query, color);

  &:hover .mdc-line-ripple {
    @include line-ripple-mixins.inactive-color($color, $query: $query);
  }
}

@mixin line-ripple-color_($color, $query: feature-targeting.all()) {
  .mdc-line-ripple {
    @include line-ripple-mixins.active-color($color, $query: $query);
  }
}

@mixin hover-outline-color_($color, $query: feature-targeting.all()) {
  &:not(.mdc-text-field--focused):hover {
    .mdc-notched-outline {
      @include notched-outline-mixins.color($color, $query: $query);
    }
  }
}

@mixin focused-outline-color_($color, $query: feature-targeting.all()) {
  &.mdc-text-field--focused {
    @include notched-outline-mixins.color($color, $query: $query);
  }
}

@mixin label-ink-color_($color, $query: feature-targeting.all()) {
  .mdc-floating-label {
    @include floating-label-mixins.ink-color($color, $query: $query);
  }
}

@mixin _prefix-color($color, $query: feature-targeting.all()) {
  $feat-color: feature-targeting.create-target($query, color);

  @include feature-targeting.targets($feat-color) {
    .mdc-text-field__affix--prefix {
      @include theme.property(color, $color);
    }
  }
}

@mixin _suffix-color($color, $query: feature-targeting.all()) {
  $feat-color: feature-targeting.create-target($query, color);

  @include feature-targeting.targets($feat-color) {
    .mdc-text-field__affix--suffix {
      @include theme.property(color, $color);
    }
  }
}

// Selectors

@mixin placeholder-selector_ {
  // GSS will combine selectors with the same content, and some browsers have a
  // CSS quirk where it drops a rule if it does not recognize one of the
  // selectors.
  // To avoid GSS combining the ::placeholder and :-ms-input-placeholder
  // selectors, we wrap them in `@media all`.
  // TODO(b/142329051)
  @media all {
    // ::placeholder needs to be wrapped because IE11 will drop other selectors
    // with the same content
    &::placeholder {
      @content;
    }
  }

  @media all {
    // :-ms-input-placeholder needs to be wrapped because Firefox will drop
    // other selectors with the same content
    &:-ms-input-placeholder {
      @content;
    }
  }
}

// State qualifiers

///
/// Helps style the text-field only when it's enabled.
/// @access private
///
@mixin if-enabled_ {
  &:not(.mdc-text-field--disabled) {
    @content;
  }
}

///
/// Helps style the text-field only when it's disabled.
/// @access private
///
@mixin if-disabled_ {
  &.mdc-text-field--disabled {
    @content;
  }
}
